// 1-2 异常处理-标准异常
/**
 * C++ 异常处理
 * 异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况，比如尝试除以零的操作。

 * 异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字：try、catch、throw。

      throw: 当问题出现时，程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
      catch: 在您想要处理问题的地方，通过异常处理程序捕获异常。catch 关键字用于捕获异常。
      try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。

  * 如果有一个块抛出一个异常，捕获异常的方法会使用 try 和 catch 关键字。try 块中放置可能抛出异常的代码，try 块中的代码被称为保护代码。使用 try/catch 语句的语法如下所示：

      try
      {
        // 保护代码
      }catch( ExceptionName e1 )
      {
        // catch 块
      }catch( ExceptionName e2 )
      {
        // catch 块
      }catch( ExceptionName eN )
      {
        // catch 块
      }
    
 * 如果 try 块在不同的情境下会抛出不同的异常，这个时候可以尝试罗列多个 catch 语句，用于捕获不同类型的异常。
 * 
 * -----------start-------------------
 * 标准的异常
 * C++ 提供了一系列标准的异常，定义在 <exception> 中，我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的，如下所示：
 * 
 *  ———————————————————————— > std::exception 
 *  |                                   
 *  |                              ——————— std::domain_error
 *  |                              |
 *  | <———— std::bad_alloc         | <———— std::invalid_argumnet
 *  | <———— std::bad_cast          | <———— std::length_error
 *  | <———— std::bad_typeid        | <———— std::out_of_range
 *  | <———— std::bad_exception     |
 *  | <———— std::logic_error    <———
 *  | 
 *  ——————— std::runtime_error ——| <——— std::overflow_error
 *                               | <——— std::range_error
 *                               | <——— std::underflow_error
 * 
 * 下表是对上面层次结构中出现的每个异常的说明：
 *    异常	                描述
      std::exception	      该异常是所有标准 C++ 异常的父类。
      std::bad_alloc	      该异常可以通过 new 抛出。
      std::bad_cast	        该异常可以通过 dynamic_cast 抛出。
      std::bad_exception	  这在处理 C++ 程序中无法预期的异常时非常有用。
      std::bad_typeid	      该异常可以通过 typeid 抛出。
      std::logic_error	    理论上可以通过**读取代码**来检测到的异常。
      std::domain_error	    当使用了一个**无效的数学域**时，会抛出该异常。
      std::invalid_argument	当使用了无效的参数时，会抛出该异常。
      std::length_error	    当创建了太长的 std::string 时，会抛出该异常。
      std::out_of_range	    该异常可以通过方法抛出，例如 std::vector 和 std::bitset<>::operator[]()。
      std::runtime_error	  理论上不可以通过读取代码来检测到的异常。
      std::overflow_error	  当发生数学上溢时，会抛出该异常。
      std::range_error	    当尝试存储超出范围的值时，会抛出该异常。
      std::underflow_error	当发生数学下溢时，会抛出该异常。
 * -----------end-------------------
 * 
*/

#include <iostream>
#include <ctime>
int main(void)
{
  std::string str;
  srand((unsigned)time(NULL));

  try
  {
    // 这个触发不了，不知道std::length_error咋触发
    // 1000000
    // while (str.length() < 100000)
    // {
    //   char ch = rand() % 26 + 65 + 32;
    //   int is_upper = rand() % 2;
    //   if (is_upper)
    //   {
    //     ch -= 32;
    //   }
    //   char t[2];
    //   t[0] = ch;
    //   t[1] = '\0';

    //   str += t;
    // }

    // throw std::exception();
    // throw std::bad_alloc();
    // throw std::bad_cast();
    // throw std::bad_typeid();
    // throw std::bad_exception();

    // throw std::runtime_error();// 无匹配参数列表的构造函数

    // throw std::domain_error(); // 无匹配的构造函数
    // throw std::length_error(); // 无匹配的构造函数
  }
  catch (std::length_error err)
  {
    std::cerr << err.what() << std::endl;
  }
  catch (std::bad_exception err)
  {
    std::cerr << err.what() << std::endl;
  }
  catch (...)
  {
    std::cerr << "error" << std::endl;
  }
  // std::cout << "str : " << str << std::endl;

  printf("-------------end-----------\n");
  return 0;
}